#include "tcp_receiver.hh"

#include "tcp_header.hh"
#include "tcp_segment.hh"
#include "wrapping_integers.hh"

#include <cstdint>

// Dummy implementation of a TCP receiver

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

void TCPReceiver::push_payload(const TCPSegment &seg) {
    const TCPHeader &header = seg.header();
    _abso_seqno = unwrap(header.seqno, _isn, _abso_seqno);
    _reassembler.push_substring(seg.payload().copy(), _abso_seqno - !header.syn, header.fin);
}
void TCPReceiver::segment_received(const TCPSegment &seg) {
    const TCPHeader &header = seg.header();
    switch (_curstate) {
        case LISTEN:
            if (header.syn) {
                _isn = header.seqno;
                push_payload(seg);
                _ackno = _isn + seg.length_in_sequence_space();
                _curstate = SYN_RECV;
            }
            break;
        case SYN_RECV:
            push_payload(seg);
            _ackno = wrap(stream_out().bytes_written(), _isn) + 1;
            if (stream_out().input_ended()) {
                _ackno.emplace(_ackno.value().raw_value() + 1);
                _curstate = FIN_RECV;
            }
            break;
        case FIN_RECV:
            // _ackno.reset();
            break;
        default:
            break;
    }
}

optional<WrappingInt32> TCPReceiver::ackno() const { return _ackno; }

size_t TCPReceiver::window_size() const { return stream_out().remaining_capacity(); }
